﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MM.Commmon.UI
{
    public partial class FrmCheckinPhoto : FrmFunctionBase
    {
        private string _age;
        private string _name;
        private string _sex;
        private const int CON_WIDTH = 3;
        private int hHwnd;
        private bool isDowned;
        private bool rectReady;
        private Pen pen;
        private Rectangle recBM;
        private Rectangle recLB;
        private Rectangle recLM;
        private Rectangle recLT;
        private Rectangle recRB;
        private Rectangle recRM;
        private Rectangle recRT;
        private Rectangle rect;
        private Rectangle recTM;
        private Rectangle rectPer;
        private Brush brush;
        private UIState _curState;
        private RectPosition curRecPos;
        private Image baseImage;
        private Graphics mainPainter;
        private Point downPoint;

        public FrmCheckinPhoto()
        {
            this.pen = new Pen(Brushes.Blue);
            this.brush = Brushes.Blue;
            this.rect = new Rectangle();
            this.rectPer = new Rectangle();
            this.recRT = new Rectangle(0, 0, 6, 6);
            this.recLT = new Rectangle(0, 0, 6, 6);
            this.recLB = new Rectangle(0, 0, 6, 6);
            this.recRB = new Rectangle(0, 0, 6, 6);
            this.recTM = new Rectangle(0, 0, 6, 6);
            this.recBM = new Rectangle(0, 0, 6, 6);
            this.recLM = new Rectangle(0, 0, 6, 6);
            this.recRM = new Rectangle(0, 0, 6, 6);
            this.curRecPos = RectPosition.None;
            this.InitializeComponent();
        }

        public FrmCheckinPhoto(string name, string sex, string age)
            : this()
        {
            this._name = name;
            this._sex = sex;
            this._age = age;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            base.DialogResult = DialogResult.Cancel;
            base.Close();
        }

        private void btnCapTure_Click(object sender, EventArgs e)
        {
            this.OpenCapture();
        }

        private void btnCut_Click(object sender, EventArgs e)
        {
            this.Cut();
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            base.DialogResult = DialogResult.OK;
            base.Close();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            this.Cap();
        }

        private void Cap()
        {
            this.baseImage = null;
            SendMessage(this.hHwnd, 0x41e, 0, 0);
            IDataObject dataObject = Clipboard.GetDataObject();
            if (dataObject.GetDataPresent(typeof(Bitmap)))
            {
                this.baseImage = (Image)dataObject.GetData(typeof(Bitmap));
            }
            SendMessage(this.hHwnd, 0x40b, 0, 0);
            DestroyWindow(this.hHwnd);
            if (this.baseImage != null)
            {
                Bitmap bitmap = new Bitmap(this.baseImage, new Size(this.panVedio.Width, this.panVedio.Height));
                this.baseImage = bitmap;
                this.mainPainter = this.panVedio.CreateGraphics();
                this.rect = new Rectangle((this.panVedio.Width - this.panPhoto.Width) / 2, (this.panVedio.Height - this.panPhoto.Height) / 2, this.panPhoto.Width, this.panPhoto.Height);
                this.rectReady = true;
                this.DrawRect();
            }
            this.CurState = UIState.截取;
        }

        [DllImport("avicap32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int capCreateCaptureWindowA([MarshalAs(UnmanagedType.VBByRefStr)] ref string lpszWindowName, int dwStyle, int x, int y, int nWidth, short nHeight, int hWndParent, int nID);
        [DllImport("avicap32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool capGetDriverDescriptionA(short wDriver, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpszName, int cbName, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpszVer, int cbVer);
        [DllImport("vicap32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool capSetCallbackOnFrame(int hwnd, string s);
        [DllImport("vfw32.dll")]
        public static extern string capVideoStreamCallback(int hwnd, videohdr_tag videohdr_tag);
        private void Cut()
        {
            Image image = new Bitmap(this.rect.Width, this.rect.Height);
            Graphics.FromImage(image).DrawImage(this.baseImage, 0, 0, this.rect, GraphicsUnit.Pixel);
            this.panPhoto.BackgroundImage = image;
        }

        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool DestroyWindow(int hndw);

        private void DrawRect()
        {
            Image image = (Image)this.baseImage.Clone();
            Graphics graphics = Graphics.FromImage(image);
            graphics.DrawRectangle(this.pen, this.rect);
            this.recRT.X = (this.rect.X + this.rect.Width) - 3;
            this.recRT.Y = this.rect.Y - 3;
            graphics.FillRectangle(this.brush, this.recRT);
            this.recLT.X = this.rect.X - 3;
            this.recLT.Y = this.rect.Y - 3;
            graphics.FillRectangle(this.brush, this.recLT);
            this.recLB.X = this.rect.X - 3;
            this.recLB.Y = (this.rect.Y + this.rect.Height) - 3;
            graphics.FillRectangle(this.brush, this.recLB);
            this.recRB.X = (this.rect.X + this.rect.Width) - 3;
            this.recRB.Y = (this.rect.Y + this.rect.Height) - 3;
            graphics.FillRectangle(this.brush, this.recRB);
            this.recTM.X = (this.rect.X + (this.rect.Width / 2)) - 3;
            this.recTM.Y = this.rect.Y - 3;
            graphics.FillRectangle(this.brush, this.recTM);
            this.recBM.X = (this.rect.X + (this.rect.Width / 2)) - 3;
            this.recBM.Y = (this.rect.Y + this.rect.Height) - 3;
            graphics.FillRectangle(this.brush, this.recBM);
            this.recLM.X = this.rect.X - 3;
            this.recLM.Y = (this.rect.Y + (this.rect.Height / 2)) - 3;
            graphics.FillRectangle(this.brush, this.recLM);
            this.recRM.X = (this.rect.X + this.rect.Width) - 3;
            this.recRM.Y = (this.rect.Y + (this.rect.Height / 2)) - 3;
            graphics.FillRectangle(this.brush, this.recRM);
            this.mainPainter.DrawImage(image, 0, 0);
            image.Dispose();
        }

        private void FrmCheckinPhoto_Load(object sender, EventArgs e)
        {
            this.lbName.Text = this._name;
            this.lbSex.Text = this._sex;
            this.lbAge.Text = this._age;
            this.OpenCapture();
        }

        private void OpenCapture()
        {
            int width = this.panVedio.Width;
            int height = this.panVedio.Height;
            int wParam = 0;
            string lpszWindowName = wParam.ToString();
            this.hHwnd = capCreateCaptureWindowA(ref lpszWindowName, 0x50000000, 0, 0, 640, 480, this.panVedio.Handle.ToInt32(), 0);
            this.Text = "拍照窗口(驱动:" + lpszWindowName + ")";
            if (SendMessage(this.hHwnd, 0x40a, wParam, 0) > 0)
            {
                SendMessage(this.hHwnd, 0x435, -1, 0);
                SendMessage(this.hHwnd, 0x434, 0x42, 0);
                SendMessage(this.hHwnd, 0x432, -1, 0);
                SetWindowPos(this.hHwnd, 1, 0, 0, width, height, 6);
            }
            else
            {
                DestroyWindow(this.hHwnd);
            }
            this.CurState = UIState.视频;
        }

        private void panVedio_DoubleClick(object sender, EventArgs e)
        {
            if ((((MouseEventArgs)e).Button == MouseButtons.Left) && this.rect.Contains(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y))
            {
                this.Cut();
            }
        }

        private void panVedio_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.isDowned = true;
                if (!this.rectReady)
                {
                    this.rect.X = e.X;
                    this.rect.Y = e.Y;
                }
                else
                {
                    this.rectPer = this.rect;
                    if (this.recRT.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.RT;
                        Cursor.Current = Cursors.SizeNESW;
                    }
                    if (this.recLT.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.LT;
                        Cursor.Current = Cursors.SizeNWSE;
                    }
                    if (this.recLB.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.LB;
                        Cursor.Current = Cursors.SizeNESW;
                    }
                    if (this.recRB.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.RB;
                        Cursor.Current = Cursors.SizeNWSE;
                    }
                    if (this.recTM.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.TM;
                        Cursor.Current = Cursors.SizeNS;
                    }
                    if (this.recBM.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.BM;
                        Cursor.Current = Cursors.SizeNS;
                    }
                    if (this.recLM.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.LM;
                        Cursor.Current = Cursors.SizeWE;
                    }
                    if (this.recRM.Contains(e.X, e.Y))
                    {
                        this.curRecPos = RectPosition.RM;
                        Cursor.Current = Cursors.SizeWE;
                    }
                }
                this.downPoint = new Point(e.X, e.Y);
            }
            if (e.Button == MouseButtons.Right)
            {
                if (!this.rectReady)
                {
                    base.Close();
                }
                else
                {
                    this.mainPainter.DrawImage(this.baseImage, 0, 0);
                    this.rectReady = false;
                }
            }
        }

        private void panVedio_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.recRT.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNESW;
            }
            else if (this.recLT.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNWSE;
            }
            else if (this.recLB.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNESW;
            }
            else if (this.recRB.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNWSE;
            }
            else if (this.recTM.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNS;
            }
            else if (this.recBM.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeNS;
            }
            else if (this.recLM.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeWE;
            }
            else if (this.recRM.Contains(e.X, e.Y))
            {
                Cursor.Current = Cursors.SizeWE;
            }
            else
            {
                Cursor.Current = Cursors.Default;
            }
            if (this.isDowned)
            {
                if (!this.rectReady)
                {
                    int width = 0;
                    int height = 0;
                    if (e.Y < this.rect.Y)
                    {
                        height = this.downPoint.Y - e.Y;
                    }
                    else
                    {
                        height = e.Y - this.downPoint.Y;
                    }
                    if (e.X < this.rect.X)
                    {
                        width = this.downPoint.X - e.X;
                    }
                    else
                    {
                        width = e.X - this.downPoint.X;
                    }
                    this.rect.X = Math.Min(this.downPoint.X, e.X);
                    this.rect.Y = Math.Min(this.downPoint.Y, e.Y);
                    this.rect.Size = new Size(width, height);
                }
                else
                {
                    switch (this.curRecPos)
                    {
                        case RectPosition.RT:
                            this.rect.Y = this.rectPer.Y + (e.Y - this.downPoint.Y);
                            this.rect.Height = this.rectPer.Height - (e.Y - this.downPoint.Y);
                            this.rect.Width = this.rectPer.Width + (e.X - this.downPoint.X);
                            break;

                        case RectPosition.LT:
                            this.rect.X = e.X;
                            this.rect.Width = this.rectPer.Width - (e.X - this.downPoint.X);
                            this.rect.Y = this.rectPer.Y + (e.Y - this.downPoint.Y);
                            this.rect.Height = this.rectPer.Height - (e.Y - this.downPoint.Y);
                            break;

                        case RectPosition.LB:
                            this.rect.X = e.X;
                            this.rect.Width = this.rectPer.Width - (e.X - this.downPoint.X);
                            this.rect.Height = this.rectPer.Height + (e.Y - this.downPoint.Y);
                            break;

                        case RectPosition.RB:
                            this.rect.Height = this.rectPer.Height + (e.Y - this.downPoint.Y);
                            this.rect.Width = this.rectPer.Width + (e.X - this.downPoint.X);
                            break;

                        case RectPosition.TM:
                            this.rect.Y = this.rectPer.Y + (e.Y - this.downPoint.Y);
                            this.rect.Height = this.rectPer.Height - (e.Y - this.downPoint.Y);
                            break;

                        case RectPosition.BM:
                            this.rect.Height = this.rectPer.Height + (e.Y - this.downPoint.Y);
                            break;

                        case RectPosition.LM:
                            this.rect.X = e.X;
                            this.rect.Width = this.rectPer.Width - (e.X - this.downPoint.X);
                            break;

                        case RectPosition.RM:
                            this.rect.Width = this.rectPer.Width + (e.X - this.downPoint.X);
                            break;
                    }
                    if (((this.curRecPos == RectPosition.None) && this.rect.Contains(e.X, e.Y)) && this.isDowned)
                    {
                        this.rect.X = (this.rectPer.X + e.X) - this.downPoint.X;
                        this.rect.Y = (this.rectPer.Y + e.Y) - this.downPoint.Y;
                    }
                }
                this.DrawRect();
            }
        }

        private void panVedio_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (e.X < this.rect.X)
                {
                    this.rect.X = e.X;
                }
                if (e.Y < this.rect.Y)
                {
                    this.rect.Y = e.Y;
                }
                this.isDowned = false;
                this.rectReady = true;
                this.curRecPos = RectPosition.None;
            }
        }

        [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int SendMessage(int hwnd, int wMsg, int wParam, [MarshalAs(UnmanagedType.AsAny)] object lParam);
        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int SetWindowPos(int hwnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);

        // Properties
        private UIState CurState
        {
            get
            {
                return this._curState;
            }
            set
            {
                this._curState = value;
                switch (this._curState)
                {
                    case UIState.初始:
                        this.btnCapTure.Enabled = true;
                        this.btnStop.Enabled = false;
                        this.btnCut.Enabled = false;
                        return;

                    case UIState.视频:
                        this.btnCapTure.Enabled = false;
                        this.btnStop.Enabled = true;
                        this.btnCut.Enabled = false;
                        return;

                    case UIState.截取:
                        this.btnCapTure.Enabled = true;
                        this.btnStop.Enabled = false;
                        this.btnCut.Enabled = true;
                        return;
                }
            }
        }

        public Image Photo
        {
            get
            {
                return this.panPhoto.BackgroundImage;
            }
        }

        // Nested Types
        public delegate bool CallBack(int hwnd, int lParam);

        private enum RectPosition
        {
            RT = 0,
            LT = 1,
            LB = 2,
            RB = 3,
            TM = 4,
            BM = 5,
            LM = 6,
            RM = 7,
            None = 8
        }

        private enum UIState
        {
            初始 = 0,
            视频 = 1,
            截取 = 2
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct videohdr_tag
        {
            public byte[] lpData;
            public int dwBufferLength;
            public int dwBytesUsed;
            public int dwTimeCaptured;
            public int dwUser;
            public int dwFlags;
            public int[] dwReserved;
        }
    }
}
